package cn.com.gzheroli.core.util;

import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.gzheroli.core.common.model.common.SqlContext;

public class SqlUtils {
	/** 日志对象 */
	private static final Logger LOG = LoggerFactory.getLogger(SqlUtils.class);

	/**
	 * 构建insert语句
	 *
	 * @param entity
	 *            实体映射对象
	 * @param nameHandler
	 *            名称转换处理器
	 * @return
	 */
	public static SqlContext buildInsertSql(Object entity, NameHandler nameHandler) {
		Class<?> clazz = entity.getClass();
		String tableName = NameHandler.getTableName(clazz.getSimpleName());
		String primaryName = NameHandler.getPrimaryName(clazz.getSimpleName());
		StringBuilder sql = new StringBuilder("insert into ");
		List<Object> params = new ArrayList<Object>();
		sql.append(tableName);
		// 获取属性信息
		BeanInfo beanInfo = ClassUtils.getSelfBeanInfo(clazz);
		PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
		sql.append("(");
		StringBuilder args = new StringBuilder();
		args.append("(");
		for (PropertyDescriptor pd : pds) {
			Object value = getReadMethodValue(pd.getReadMethod(), entity);
			if (value == null) {
				continue;
			}
			sql.append(NameHandler.getColumnName(pd.getName()));
			args.append("?");
			params.add(value);
			sql.append(",");
			args.append(",");
		}
		if (sql.lastIndexOf(",") > -1) {
			sql.deleteCharAt(sql.length() - 1);
		}
		if (args.lastIndexOf(",") > -1) {
			args.deleteCharAt(args.length() - 1);
		}
		args.append(")");
		sql.append(")");
		if (sql.indexOf("()") > -1) {
			return new SqlContext(new StringBuilder(), primaryName, params);
		}

		sql.append(" values ");
		sql.append(args);
		return new SqlContext(sql, primaryName, params);
	}

	/**
	 * 构建更新sql
	 * 
	 * @param entity
	 * @param nameHandler
	 * @return
	 */
	public static SqlContext buildUpdateSql(Object entity, NameHandler nameHandler) {
		Class<?> clazz = entity.getClass();
		StringBuilder sql = new StringBuilder();
		List<Object> params = new ArrayList<Object>();
		String tableName = NameHandler.getTableName(clazz.getSimpleName());
		String primaryName = NameHandler.getPrimaryName(clazz.getSimpleName());
		// 获取属性信息
		BeanInfo beanInfo = ClassUtils.getSelfBeanInfo(clazz);
		PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
		sql.append("update ");
		sql.append(tableName);
		sql.append(" set ");
		Object primaryValue = null;
		for (PropertyDescriptor pd : pds) {
			Object value = getReadMethodValue(pd.getReadMethod(), entity);
			if (value == null) {
				continue;
			}
			String columnName = NameHandler.getColumnName(pd.getName());
			if (primaryName.equalsIgnoreCase(columnName)) {
				primaryValue = value;
			}
			sql.append(columnName);
			sql.append(" = ");
			sql.append("?");
			params.add(value);
			sql.append(",");
		}
		if (sql.lastIndexOf(",") > -1) {
			sql.deleteCharAt(sql.length() - 1);
		}
		if (sql.toString().trim().endsWith("set")) {
			return new SqlContext(new StringBuilder(), primaryName, params);
		}
		sql.append(" where ");
		sql.append(primaryName);
		sql.append(" = ?");
		params.add(primaryValue);
		return new SqlContext(sql, primaryName, params);
	}

	/**
	 * 构建更新sql
	 * 
	 * @param entity
	 * @param nameHandler
	 * @return
	 */
	public static Map buildUpdateSql(Map parameters, Map whereMap, Map columnMap, NameHandler nameHandler) {
		Map retMap = new HashMap();
		List params = new ArrayList();
		StringBuilder sql = new StringBuilder();
		sql.append("update ");
		sql.append(parameters.get("tableName"));
		sql.append(" set ");
		List colNameList = (List) columnMap.get("coloumnName");
		Iterator parait = parameters.keySet().iterator();
		while (parait.hasNext()) {
			String paraKey = parait.next().toString();
			String columnName = NameHandler.getColumnName(paraKey);
			if (!colNameList.contains(columnName) || whereMap.containsKey(paraKey)) {
				continue;
			}

			/*
			 * if (primaryName.equalsIgnoreCase(columnName)) { primaryValue = value; }
			 */
			sql.append(columnName);
			sql.append("=");
			sql.append("?");
			params.add(parameters.get(paraKey));
			sql.append(",");
		}
		if (sql.lastIndexOf(",") > -1) {
			sql.deleteCharAt(sql.length() - 1);
		}
		if (sql.toString().trim().endsWith("set")) {
			return null;
		}
		sql.append(" where ");
		Iterator whereit = whereMap.keySet().iterator();
		String whereStr = "";
		while (whereit.hasNext()) {
			String wherePara = whereit.next().toString();
			String columnName = NameHandler.getColumnName(wherePara);
			if (!colNameList.contains(columnName)) {
				continue;
			}
			whereStr = " and " + columnName;
			whereStr = whereStr + "=?";
			params.add(whereMap.get(wherePara));
		}
		if (whereStr.trim().startsWith("and")) {
			whereStr = whereStr.trim().substring(whereStr.indexOf("and") + 3) + " ";
		}
		sql.append(whereStr);
		retMap.put("sql", sql.toString());
		retMap.put("params", params);
		return retMap;
	}

	/**
	 * 构建查询条件
	 * 
	 * @param entity
	 * @param nameHandler
	 */
	public static SqlContext buildQueryCondition(Object entity, NameHandler nameHandler) {
		// 获取属性信息
		BeanInfo beanInfo = ClassUtils.getSelfBeanInfo(entity.getClass());
		// PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(entityClass);
		PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
		StringBuilder condition = new StringBuilder();
		List<Object> params = new ArrayList<Object>();
		int count = 0;
		for (PropertyDescriptor pd : pds) {
			Object value = getReadMethodValue(pd.getReadMethod(), entity);
			if (value == null) {
				continue;
			}
			if (count > 0) {
				condition.append(" and ");
			}
			condition.append(NameHandler.getColumnName(pd.getName()));
			condition.append(" = ?");
			params.add(value);
			count++;
		}
		return new SqlContext(condition, null, params);
	}

	/**
	 * 获取属性值
	 *
	 * @param readMethod
	 * @param entity
	 * @return
	 */
	private static Object getReadMethodValue(Method readMethod, Object entity) {
		if (readMethod == null) {
			return null;
		}
		try {
			if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
				readMethod.setAccessible(true);
			}
			return readMethod.invoke(entity);
		} catch (Exception e) {
			LOG.error("获取属性值失败", e);
			throw new RuntimeException(e);
		}
	}
}
